﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls;
using System.Collections.ObjectModel;
using Axe.Extensions;
using System.Web.UI;
using Axe.Data.Mapping;
using System.ComponentModel;

namespace Axe.Web.Controls
{
    [Serializable]
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public class FilterItem :IStateManager
    {
        public ConditionOperator Operator { get; set; }
        public string FieldName { get; set; }
        public string FieldValue { get; set; }

        #region IStateManager Members

        public bool IsTrackingViewState
        {
            get { return true; }
        }

        public void LoadViewState(object state)
        {
            Triplet t = (Triplet)state;
            Operator = (ConditionOperator)t.First;
            FieldName = (string)t.Second;
            FieldValue = (string)t.Third;
        }

        public object SaveViewState()
        {
            return new Triplet(Operator, FieldName, FieldValue);
        }

        public void TrackViewState()
        {
            
        }

        #endregion

        public FilterItem()
        {
            FieldName = "";
            FieldValue = "";
            Operator = ConditionOperator.Equals;
        }

        public string ConstructSqlOperand(bool useParams, string paramName)
        {
            
            string op = SqlClauseBuilder.GetOperator(Operator);

            if (useParams)
                return String.Format("{0} {1} @{2}", FieldName, op,paramName);
            else
                return String.Format("{0} {1} {2}", FieldName, op,FieldValue);
        }
    }

    [Serializable, PersistChildren(true)]
    public class StringPair : IStateManager
    {
        [NotifyParentProperty(true),PersistenceMode(PersistenceMode.Attribute)]
        public string DisplayName {get;set;}
        [NotifyParentProperty(true), PersistenceMode(PersistenceMode.Attribute)]
        public string FieldName { get; set; }

        public override string ToString()
        {
            return String.Format("{0} ({1})", DisplayName,FieldName);
        }

        public StringPair() { }
        public StringPair(string name, string display)
        {
            FieldName = name;
            DisplayName = display;
        }

        #region IStateManager Members

        bool IStateManager.IsTrackingViewState
        {
            get { return true; }
        }

        void IStateManager.LoadViewState(object state)
        {
            object[] data = (object[])state;
            FieldName = (string)data[0];
            DisplayName = (string)data[1];
        }

        object IStateManager.SaveViewState()
        {
            return new object[] { FieldName, DisplayName };
        }

        void IStateManager.TrackViewState()
        {
        }

        #endregion
    }
    
    public class FilterEventArgs : EventArgs
    {
        List<FilterItem> m_Items;

        public List<FilterItem> Items
        {
            get { return m_Items; }
            set { m_Items = value; }
        }

        public FilterEventArgs()
        {}

        public FilterEventArgs(List<FilterItem> items)
        { m_Items=items;}
    }

    public class SqlFilteringControl : CompositeControl
    {
        #region public Collection<StringPair> DataFields
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public virtual Collection<StringPair> DataFields
        {
            get { return ViewState.Get("DataFields", new Collection<StringPair>()); }
            set { ViewState["DataFields"] = value; }
        } 
        #endregion

        #region public int ClausesCount
        [DefaultValue(1)]
        public int ClausesCount
        {
            get { return ViewState.Get("ClausesCount", 1); }
            set { ViewState["ClausesCount"] = value; }
        } 
        #endregion

        #region public string FilterText
        public string FilterText
        {
            get { return m_ExecuteFilterButton.Text; }
            set { m_ExecuteFilterButton.Text = value; }
        } 
        #endregion

        protected virtual void OnFilterEvent(List<FilterItem> items)
        {
            if (FilterEvent != null)
                FilterEvent(this, new FilterEventArgs(items));
        }

        public event EventHandler<FilterEventArgs> FilterEvent;

        public SqlFilteringControl()
        {
            m_ExecuteFilterButton.ID = "DoFilter";
            m_ExecuteFilterButton.Click += new EventHandler(m_ExecuteFilterButton_Click);
        }

        void m_ExecuteFilterButton_Click(object sender, EventArgs e)
        {
            List<FilterItem> items = GetDataItems();
            OnFilterEvent(items);
        }

        #region private List<FilterItem> GetDataItems()
        private List<FilterItem> GetDataItems()
        {
            List<FilterItem> items = new List<FilterItem>();

            for (int i = 0; i < ClausesCount; i++)
            {
                HardcodedDropDownList dataField = (HardcodedDropDownList)FindControl(String.Format("Field_{0}", i));
                ClauseOpList dataClause = (ClauseOpList)FindControl(String.Format("Clause_{0}", i));
                TextBox dataValue = (TextBox)FindControl(String.Format("Value_{0}", i));

                FilterItem item = new FilterItem();
                item.FieldName = dataField.SelectedValue;
                item.FieldValue = dataValue.Text;
                item.Operator = dataClause.SelectedEnum;

                items.Add(item);
            }
            return items;
        } 
        #endregion

        Button m_ExecuteFilterButton = new Button();

        List<FilterItem> itemsToBind = null;

        private void BindDataItems(List<FilterItem> items)
        {
            ClausesCount = items.Count;
            Controls.Clear();
            CreateControlHierarchy();
            ClearChildViewState();

            ChildControlsCreated = true;
            itemsToBind = items;
        }

        private Control[] CreateClauseControls(int clauseNumber)
        {
            HardcodedDropDownList dataField = new HardcodedDropDownList();
            dataField.ID = String.Format("Field_{0}",clauseNumber);
            dataField.RequestDataItems += new EventHandler<HardcodedDropDownListEventArgs>(dataField_RequestDataItems);
            
            ClauseOpList dataClause = new ClauseOpList();
            dataClause.ID = String.Format("Clause_{0}",clauseNumber);

            TextBox dataValue = new TextBox();
            dataValue.ID = String.Format("Value_{0}",clauseNumber);
            
            return new Control[] { dataField, dataClause, dataValue };
        }

        void dataField_RequestDataItems(object sender, HardcodedDropDownListEventArgs e)
        {
            foreach (StringPair p in DataFields)
            {
                e.BoundItems.Add(new ListItem(p.DisplayName, p.FieldName));
            }
        }

        private Control[] CreateCommandButtons(int posNumber)
        {
            Button add = new Button();
            add.Text = "+";
            add.CommandName = "Add";
            add.CommandArgument = posNumber.ToString();
            add.ID = String.Format("Add_{0}", posNumber.ToString());
            add.Command += new CommandEventHandler(btn_Command);

            Button del = new Button();
            del.Text = "-";
            del.CommandName = "Del";
            del.CommandArgument = posNumber.ToString();
            del.ID = String.Format("Del_{0}", posNumber.ToString());
            del.Command += new CommandEventHandler(btn_Command);
            return new Control[] { add,del};
        }

        void btn_Command(object sender, CommandEventArgs e)
        {
            int btnId;
            if (int.TryParse((string)e.CommandArgument, out btnId))
            {
                switch (e.CommandName)
                {
                    case "Del":
                        {
                            List<FilterItem> items = GetDataItems();
                            items.RemoveAt(btnId);
                            if (items.Count == 0)
                                items.Add(new FilterItem());
                            BindDataItems(items);
                        }; break;

                    case "Add":
                        {
                            List<FilterItem> items = GetDataItems();
                            items.Insert(btnId+1, new FilterItem());
                            BindDataItems(items);
                        }; break;
                }
            }
        }

        protected override void CreateChildControls()
        {
            Controls.Clear();
            CreateControlHierarchy();

            ClearChildViewState();
            ChildControlsCreated = true;
        }

        protected override void OnPreRender(EventArgs e)
        {
            PrepareControlsForRendering();
            base.OnPreRender(e);
        }

        private void PrepareControlsForRendering()
        {
            if (itemsToBind == null)
                return;

            for (int i = 0; i < ClausesCount; i++)
            {
                HardcodedDropDownList dataField = (HardcodedDropDownList)FindControl(String.Format("Field_{0}", i));
                ClauseOpList dataClause = (ClauseOpList)FindControl(String.Format("Clause_{0}", i));
                TextBox dataValue = (TextBox)FindControl(String.Format("Value_{0}", i));

                FilterItem item = itemsToBind[i];
                if (!String.IsNullOrEmpty(item.FieldName))
                    dataField.SelectedValue = item.FieldName;

                dataValue.Text = item.FieldValue;
                dataClause.SelectedEnum = item.Operator;
            }
        }

        private void CreateControlHierarchy()
        {
            for (int i = 0; i < ClausesCount; i++)
            {
                Control[] controls1 = CreateClauseControls(i);
                Control[] controls2 = CreateCommandButtons(i);

                Controls.Add(controls1);
                Controls.Add(controls2);
                Controls.Add(new LiteralControl("<br />"));
            }

            Controls.Add(m_ExecuteFilterButton);
        }
    }
}
